<?php

namespace App\Services;

use App\Exceptions\ApiException;
use App\Services\Utils\VerifyDate;
use PHPUnit\Util\Exception;

/**
 * 照片档案卷内目录
 */
class PhotoCatalogService extends BaseService
{
    /**
     * 添加或编辑
     *
     * @param $partCompanyId
     * @param $photoClassifyId
     * @param $params
     * @return bool
     * @throws ApiException
     * @author: lxk
     * @date: 2024-09-11 14:26
     */
    public function addOrUpdate($partCompanyId, $photoClassifyId, $params): bool
    {
        $photoArchiveInstance = $this->getPhotoArchiveInstance($partCompanyId, $photoClassifyId);
        $photoCatalogInstance = $this->getPhotoCatalogInstance($partCompanyId, $photoClassifyId);
        if (isset($params['id']) && $params['id'] && !$params['is_insert']) { //更新数据
            $photoCatalog = $photoCatalogInstance->find($params['id']);
            $serialNo     = $params['serial_no'];
        } else {
            $photoCatalog = $photoCatalogInstance;
            $info         = $photoCatalog->where('photo_archives_id', $params['photo_archive_id'])->latest('serial_no')->select('serial_no')->first();
            $serialNo     = $info ? $info->serial_no + 1 : 1;
        }
        $photoDate = isset($params['photo_date']) ? format_str($params['photo_date']) : '';
        if ($photoDate && !VerifyDate::check($photoDate)) {
            throw new ApiException('日期不合法，不被保存');
        }
        $photoCatalog->photo_archives_id = $params['photo_archive_id'];
        $photoCatalog->serial_no         = $serialNo;
        $photoCatalog->negative_no       = isset($params['negative_no']) ? format_str($params['negative_no']) : ''; //底片号
        $photoCatalog->page_num          = isset($params['page_num']) ? to_int($params['page_num']) : '';
        $photoCatalog->title             = isset($params['title']) ? format_str($params['title']) : '题名';
        $photoCatalog->remark            = isset($params['remark']) ? format_str($params['remark']) : '';
        $photoCatalog->file_url          = isset($params['file_url']) ?? '';
        $photoCatalog->photo_date        = $photoDate;
        $photoCatalog->photo_user        = isset($params['photo_user']) ? format_str($params['photo_user']) : '';
        $photoCatalog->creator_id        = user_id();

        $photoArchiveInstance->where('id', $params['photo_archive_id'])->update(['is_need_check' => 1]);

        return $photoCatalog->save();
    }

    /**
     * 照片档案卷内
     */
    public function getList($partCompanyId, $photoClassifyId, $photoArchiveId, $keyword)
    {
        $photoCatalogInstance = $this->getPhotoCatalogInstance($partCompanyId, $photoClassifyId);
        $list = $photoCatalogInstance
            ->where('photo_archives_id', $photoArchiveId)
            ->when($keyword, function ($query) use ($keyword) {
                $query->where('title', 'like', "%{$keyword}%");
            })
            ->orderBy('serial_no')
            ->get();
        if ($list->isEmpty()) return [];
        $list = $list->toArray();
        foreach ($list as &$val) {
            $val['file_url'] = to_int($val['file_url']);
        }

        return $list;
    }

    /**
     * 检查卷内目录数据合法性
     */
    public function checkPhotoCatalogData($photoArchiveInstance, $photoCatalogInstance, $photoArchiveId)
    {
        $list = $photoCatalogInstance
            ->where('photo_archives_id', $photoArchiveId)
            ->select('id', 'serial_no', 'photo_archives_id', 'title', 'page_num', 'photo_date')
            ->orderBy('serial_no')
            ->get();

        $catalogRedisKey = get_rand_str('is_photo_catalog_has_problem'); //记录卷内是否有异常
        redis()->setex($catalogRedisKey, 300, 0); //初始值为0，有效期300秒

        if ($list->isNotEmpty()) {
            $catalogs  = $list->toArray();
            $serialNos = array_column($catalogs, 'serial_no');
            if (!$this->checkSerialNo($serialNos)) {
                redis()->incrby($catalogRedisKey, 1);
                PhotoArchivesService::problemMark($photoArchiveInstance, to_array($photoArchiveId), '照片/底片号不合法');
            }
            foreach ($catalogs as $val) {
                $id = to_array($val['id']);
                if (!$val['title']) {
                    redis()->incrby($catalogRedisKey, 1);
                    self::problemMark($photoCatalogInstance, $id, '题名为空', $photoArchiveInstance, $photoArchiveId);
                }
                if (!$val['photo_date']) {
                    redis()->incrby($catalogRedisKey, 1);
                    self::problemMark($photoCatalogInstance, $id, '拍摄时间为空', $photoArchiveInstance, $photoArchiveId);
                }
                if (!VerifyDate::check($val['photo_date'])) {
                    redis()->incrby($catalogRedisKey, 1);
                    self::problemMark($photoCatalogInstance, $id, '拍摄时间不合法', $photoArchiveInstance, $photoArchiveId);
                }
                if (!redis()->get($catalogRedisKey)) { //如果卷内没异常，去掉卷内标记
                    self::removeMark($photoCatalogInstance, $id, $photoArchiveInstance, $photoArchiveId);
                }
            }
            $this->updatePhotoArchive($photoArchiveInstance, $photoArchiveId, $catalogs); //更新案卷目录的页次和日期字段，要求检查完一个，就更新一个
        }
    }

    /**
     * 卷内问题标记，如果卷内有问题，所属案卷也进行标记
     */
    public static function problemMark($photoCatalogInstance, $photoCatalogId, $problem, $photoArchiveInstance, $photoArchiveId)
    {
        $photoArchiveInstance->where('id', $photoArchiveId)->update(['problem' => '卷内数据异常']);
        $photoCatalogInstance->where('id', $photoCatalogId)->update(['problem' => $problem]);
    }

    /**
     * 移除问题标记，如果卷内有问题，所属案卷也进行标记
     */
    public static function removeMark($photoCatalogInstance, $bookCatalogId, $photoArchiveInstance, $photoArchiveId)
    {
        $photoArchiveInstance->where('id', $photoArchiveId)->update(['problem' => '']);
        $photoCatalogInstance->where('id', $bookCatalogId)->update(['problem' => '']);
    }

    /**
     * 检查完毕后更新一条案卷信息
     */
    public function updatePhotoArchive($photoArchiveInstance, $photoArchiveId, $list)
    {
        $noUpdate   = 0;
        $newDateArr = [];
        $dateArr    = array_column($list, 'photo_date');
        foreach ($dateArr as $date) {
            if (!VerifyDate::check($date)) { //如果有日期不合法的，不更新案卷日期
                $noUpdate = 1;
                break; //终止foreach
            }
            if (!empty($date)) {
                $newDateArr[] = $date;
            };
        }
        $photoArchiveInstance->where('id', $photoArchiveId)->update([
            'start_date' => $noUpdate ? '' : min($newDateArr),
            'end_date'   => $noUpdate ? '' : max($newDateArr),
            'page_num'   => count($list),
        ]);
    }

    /**
     * 获取卷内数据的位置
     */
    public function getCatalogPosition($partCompanyId, $photoClassifyId, $catalog)
    {
        $position = '';
        if (!$catalog['serial_no'] || !$catalog['title'] || !$catalog['photo_date'] || !$catalog['page_num']) {
            $archivesNum = $this->getArchivesNum($partCompanyId, $photoClassifyId, $catalog['photo_archives_id']);
            $catalogNum  = $catalog['serial_no'];
            $position    = "案卷序号【{$archivesNum}】,卷内序号【{$catalogNum}】";
        }
        return $position;
    }

    /**
     * 获取 案卷目录 序号
     * 注意下如果返回闭包里面的 $archivesNum的值
     */
    private function getArchivesNum($partCompanyId, $photoClassifyId, $photoArchiveId)
    {
        $photoArchivesInstance = $this->getPhotoArchiveInstance($partCompanyId, $photoClassifyId);

        return $photoArchivesInstance->where('id', $photoArchiveId)->value('serial_no');
    }

    /**
     * 检查页号格式是否合法。应为纯数字，或者 15-30 | 15~30 这种格式
     */
    public static function checkPageNum($pageNum)
    {
        if (!is_numeric($pageNum)) {
            if (!$pos = strpos($pageNum, '～')) {
                return false;
            } else {
                $smallPage = mb_substr($pageNum, 0, $pos);
                $result    = json_encode(mb_substr($pageNum, $pos + 1));
                if (!empty($result)) {
                    $bigPage = mb_substr($pageNum, $pos + 1);
                } else {
                    $bigPage = mb_substr($pageNum, $pos + 3);
                }
                if (!is_numeric($smallPage) || !is_numeric($bigPage)) {
                    return false;
                }
                if ($smallPage > $bigPage) {
                    return false;
                }
                return [
                    'small_page' => $smallPage,
                    'big_page'   => $bigPage
                ];
            }
        }
        return $pageNum;
    }

    /**
     * 检查完毕后更新一条案卷信息
     */
    public function updateOneInfo($partCompanyId, $photoClassifyId, $photoArchiveId, $catalogs)
    {
        $photoArchivesInstance = $this->getPhotoArchiveInstance($partCompanyId, $photoClassifyId);

        $firstArr  = current($catalogs);
        $endArr    = array_pop($catalogs);
        $startDate = $firstArr['photo_date'];
        $endDate   = $endArr['photo_date'];

        $pageNum = $endArr['page_num'];
        if (!is_numeric($pageNum)) {
            $page    = $this->checkPageNum($pageNum);
            $pageNum = $page['big_page'];
        }

        $photoArchivesInstance->where('id', $photoArchiveId)->update([
            'start_date' => $startDate,
            'end_date'   => $endDate,
            'page_num'   => $pageNum,
        ]);
    }

    /**
     * 删除若干数据后，剩余的数据序号和档案号重新排列，第一个序号为1 从小到大递增
     */
    public function delData($partCompanyId, $photoClassifyId, $photoArchiveId, $ids)
    {
        $photoArchivesInstance = $this->getPhotoArchiveInstance($partCompanyId, $photoClassifyId);
        $photoCatalogInstance  = $this->getPhotoCatalogInstance($partCompanyId, $photoClassifyId);

        $photoArchives = $photoArchivesInstance->find($photoArchiveId);

        if (!$photoCatalogInstance->whereIn('id', $ids)->delete()) {
            throw new ApiException('删除失败！');
        };
        $redisKey = get_rand_str('del_photo_catalog');
        redis()->set($redisKey, 0); //定义个临时变量

        $photoCatalogInstance
            ->where('photo_archives_id', $photoArchiveId)
            ->select('id', 'serial_no')
            ->orderBy('serial_no')
            ->chunkById(20, function ($list) use ($redisKey) {
                foreach ($list as $photoCatalog) {
                    redis()->incrby($redisKey, 1); //加1
                    $serialNo = redis()->get($redisKey); //获取增加后的值
                    $serialNo = $this->formatSerialNo($serialNo, 3);
                    $photoCatalog->update(['serial_no' => $serialNo]);
                }
            });
        redis()->del($redisKey); //用完删除

        $ids = implode(',', $ids);
        CommonService::addPhotoArchivesLog("删除档案照片卷内", $ids, $photoArchives->part_company_id, $photoArchives->photo_classify_id);

        return true;
    }

    /**
     * 单个卷内上传若干个PDF
     *
     * @param $partCompanyId
     * @param $photoClassifyId
     * @param $photoCatalogId
     * @param $file
     * @param $uploadResult
     * @return bool
     * @throws ApiException
     * @author: lxk
     * @date: 2024-09-20 11:26
     */
    public function addSomePhoto($partCompanyId, $photoClassifyId, $photoCatalogId, $file, $uploadResult): bool
    {
        $photoCatalogInstance = $this->getPhotoCatalogInstance($partCompanyId, $photoClassifyId);
        $info                 = $photoCatalogInstance->find($photoCatalogId);
        $info->creator_id     = user_id();
        $info->file_url       = 1; //更新字段
        $info->updated_at     = now();
        $info->save();

        $fileUrl  = $uploadResult['file'];
        $pdfName  = format_archives_no($uploadResult['origin_name']);
        $exifInfo = null;
        if ($uploadResult['file_ext'] == 'jpg') {
            $exifInfo = ExifService::getExifInfo($file);
        }
        $photoCatalogImageInstance = $this->getPhotoCatalogImageInstance($partCompanyId, $photoClassifyId);
        $photoCatalogImageInstance->insert([
            'photo_archives_id' => $info->photo_archives_id,
            'photo_catalog_id'  => $photoCatalogId,
            'file_url'          => $fileUrl,
            'origin_name'       => $pdfName,
            'file_size'         => $uploadResult['file_size'],
            'photo_time'        => $exifInfo ? date('Y-m-d H:i', strtotime($exifInfo['photo_time'])) : '',
            'photo_address'     => $exifInfo ? $exifInfo['address'] : '',
            'created_at'        => now(),
            'creator_id'        => user_id() ?: 0,
        ]);
        CommonService::addProjectActionLog("单条卷内上传PDF,卷内id={$photoCatalogId}", $photoCatalogId, $partCompanyId, $photoClassifyId);
        CommonService::isNeedUpdatePaperCount($partCompanyId, 1);

        return true;
    }

    /**
     * 获取卷内的photo列表
     *
     * @param $partCompanyId
     * @param $photoClassifyId
     * @param $photoCatalogId
     * @return mixed
     * @throws ApiException
     * @author: lxk
     * @date: 2024-09-12 14:32
     */
    public function getPhotoList($partCompanyId, $photoClassifyId, $photoCatalogId)
    {
        $photoCatalogImageInstance = $this->getPhotoCatalogImageInstance($partCompanyId, $photoClassifyId);
        $list = $photoCatalogImageInstance
            ->where('photo_catalog_id', $photoCatalogId)
            ->select('id', 'file_url', 'origin_name', 'photo_time', 'photo_address')
            ->get()
            ->toArray();

        foreach ($list as $key => &$val) {
            $count        = $key + 1;
            $val['title'] = "【第{$count}张】";
        }
        return $list;
    }

    /**
     * 删除卷内照片。一个卷内可能不止一张照片
     *
     * @param $partCompanyId
     * @param $photoClassifyId
     * @param $photoId
     * @return bool
     * @throws ApiException
     * @author: lxk
     * @date: 2024-09-13 15:05
     */
    public function delPhoto($partCompanyId, $photoClassifyId, $photoId) : bool
    {
        try {
            $catalogInstance      = $this->getPhotoCatalogInstance($partCompanyId, $photoClassifyId);
            $catalogImageInstance = $this->getPhotoCatalogImageInstance($partCompanyId, $photoClassifyId);

            $catalogImage = $catalogImageInstance->where('id', $photoId)->first();
            $fileUrl      = $catalogImage->file_url;
            $catalogId    = $catalogImage->photo_catalog_id;

            $catalogImage->where('id', $photoId)->delete();
            $count = $catalogImageInstance->where('photo_catalog_id', $catalogId)->count();
            if (empty($count)) { //删除一张照片后，判断这条卷内还有没有照片，如果没有，则更新为0
                $catalogInstance->where('id', $catalogId)->update(['file_url' => 0]);
            }
            if (CommonService::isDelOssObject()) { //如果是正式服操作，从OSS里面删除
                //$list = $catalogImageInstance->where('id', '>', 0)->pluck('file_url')->toArray();
                (new AttachmentService())->delOssFile($fileUrl);
            }
            CommonService::addProjectActionLog('删除照片', $catalogId, $partCompanyId, $photoClassifyId);
            CommonService::isNeedUpdatePaperCount($partCompanyId, 1);

            return true;
        }
        catch (Exception $exception) {
            throw new ApiException($exception->getMessage());
        }
    }

}
